package org.akomantoso.core.io;

import java.io.IOException;
import java.util.Calendar;

import org.akomantoso.core.data.attribute.Actor;
import org.akomantoso.core.data.attribute.Date;
import org.akomantoso.core.data.attribute.Enactment;
import org.akomantoso.core.data.attribute.HTMLattrs;
import org.akomantoso.core.data.attribute.IdOpt;
import org.akomantoso.core.data.attribute.IdReq;
import org.akomantoso.core.data.attribute.Link;
import org.akomantoso.core.data.attribute.LinkOpt;
import org.akomantoso.core.data.attribute.Modifiers;
import org.akomantoso.core.data.attribute.Name;
import org.akomantoso.core.data.attribute.Notes;
import org.akomantoso.core.data.attribute.Number;
import org.akomantoso.core.data.attribute.OptValue;
import org.akomantoso.core.data.attribute.Outcome;
import org.akomantoso.core.data.attribute.Pos;
import org.akomantoso.core.data.attribute.Refers;
import org.akomantoso.core.data.attribute.RefersReq;
import org.akomantoso.core.data.attribute.Role;
import org.akomantoso.core.data.attribute.Show;
import org.akomantoso.core.data.attribute.Source;
import org.akomantoso.core.data.attribute.SpeechAtts;
import org.akomantoso.core.data.attribute.Src;
import org.akomantoso.core.data.attribute.Time;
import org.akomantoso.core.data.attribute.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
public final class OutputUtil {

	private OutputUtil(){}
	
	private final static Logger LOGGER = LoggerFactory.getLogger(OutputUtil.class);
	
	public static <T extends Output> void writeMandatoryAttribute(T out,String name,String value,Object content) throws IOException {
		
		if (value == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content -> write \"\"",name,content);
			value = "";
		}
		
		out.writeAttribute(name, value);
	}
	
	public static <T extends Output> void writeMandatoryAttribute(T out,String name,@SuppressWarnings("rawtypes") Enum value,Object content) throws IOException {
		
		if (value == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",name,content);
			return;
		}
		
		out.writeAttribute(name, value.name());
	}
	
	public static <T extends Output> void writeMandatoryAttribute(T out,String name,Calendar value,Object content) throws IOException {
		
		if (value == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",name,content);
			return;
		}
		
		StringBuilder builder = new StringBuilder();
		builder.append(value.get(Calendar.YEAR)).append("-");
		int temp = value.get(Calendar.MONTH)+1;
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append("-");
		temp = value.get(Calendar.DAY_OF_MONTH);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp);
		out.writeAttribute(name, builder.toString());
	}
	
	public static <T extends Output> void writeMandatoryAttributeTimeStamp(T out,String name,Calendar value,Object content) throws IOException {
		
		if (value == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",name,content);
			return;
		}
		
		StringBuilder builder = new StringBuilder();
		builder.append(value.get(Calendar.YEAR)).append("-");
		int temp = value.get(Calendar.MONTH)+1;
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append("-");
		temp = value.get(Calendar.DAY_OF_MONTH);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append("T");
		temp = value.get(Calendar.HOUR_OF_DAY);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append(":");
		temp = value.get(Calendar.MINUTE);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append(":");
		temp = value.get(Calendar.SECOND);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append(".");
		builder.append(value.get(Calendar.MILLISECOND));
		
		out.writeAttribute(name, builder.toString());
	}
	
	
	public static <T extends Output> void writeAttribute(T out,String name,String value) throws IOException {
		if (value != null) {
			out.writeAttribute(name, value);	
		}
	}
	
	public static <T extends Output> void writeAttribute(T out,String name,@SuppressWarnings("rawtypes") Enum value) throws IOException {
		if (value != null) {
			out.writeAttribute(name, value.name());	
		}
	}
	
	///////////////////////////////////////////////////////////////////////////
	
	public static void writeIdOpt(Output out,IdOpt idOpt) throws IOException {
		if (idOpt.getId() != null) {
			out.writeAttribute(IdOpt.ATTRIBUTE_ID, idOpt.getId());
		}
		if (idOpt.getEvolvingId() != null) {
			out.writeAttribute(IdOpt.ATTRIBUTE_EVOLVING_ID, idOpt.getEvolvingId());
		}
	}
	
	public static void writeHTMLattrs(Output out,HTMLattrs htmlAttrs) throws IOException {
		if (htmlAttrs.getStyle() != null) {
			out.writeAttribute(HTMLattrs.ATTRIBUT_STYLE, htmlAttrs.getStyle());
		}
		if (htmlAttrs.getClazz() != null) {
			out.writeAttribute(HTMLattrs.ATTRIBUT_CLASS, htmlAttrs.getClazz());
		}
		if (htmlAttrs.getTitle() != null) {
			out.writeAttribute(HTMLattrs.ATTRIBUT_TITLE, htmlAttrs.getTitle());
		}
	}
	
	public static void writeEnactment(Output out,Enactment enactment) throws IOException {
		if (enactment.getPeriod() != null) {
			out.writeAttribute(Enactment.ATTRIBUTE, enactment.getPeriod());
		}
		if (enactment.getStatus() != null) {
			out.writeAttribute(Enactment.ATTRIBUTE_STATUS, enactment.getStatus().name());
		}
	}
	
	
	public static void writeModifiers(Output out,Modifiers modifiers) throws IOException {
		if (modifiers.getIncomplete() != null) {
			out.writeAttribute(Modifiers.ATTRIBUTE_INCOMPLETE, modifiers.getIncomplete().toString());
		}
		if (modifiers.getExclusion() != null) {
			out.writeAttribute(Modifiers.ATTRIBUTE_EXCLUSION, modifiers.getExclusion().toString());
		}
	}
	
	public static void writeSpeechAtts(Output out,SpeechAtts speechAtts) throws IOException {
		if (speechAtts.getBy() == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",SpeechAtts.ATTRIBUTE_BY,speechAtts);
			return;
		} else {
			out.writeAttribute(SpeechAtts.ATTRIBUTE_BY, speechAtts.getBy());
		}
		if (speechAtts.getAs() != null) {
			out.writeAttribute(SpeechAtts.ATTRIBUTE_AS, speechAtts.getAs());
		}
		if (speechAtts.getTo() != null) {
			out.writeAttribute(SpeechAtts.ATTRIBUTE_TO, speechAtts.getTo());
		}
	}
	
	
	public static void writeRefers(Output out,Refers refers) throws IOException {
		if (refers.getRefersTo() != null) {
			out.writeAttribute(Refers.ATTRIBUTE, refers.getRefersTo());
		}
	}
	
	
	public static void writeRefersReq(Output out,RefersReq refers) throws IOException {
		if (refers.getRefersTo() == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",RefersReq.ATTRIBUTE,refers);
			return;
		} else {
			out.writeAttribute(RefersReq.ATTRIBUTE, refers.getRefersTo());
		}
	}
	
	public static void writeOutcome(Output out,Outcome outcome) throws IOException {
		if (outcome.getOutcome() != null) {
			out.writeAttribute(Outcome.ATTRIBUTE, outcome.getOutcome());
		}
	}
	
	public static void writeShow(Output out,Show show) throws IOException {
		if (show.getShowAs() == null) {
			LOGGER.warn("Attribute [showAs] from Object [{}] must be not null !!! -> invalid content",show);
			return;
		} else {
			out.writeAttribute(Show.ATTRIBUTE_SHOW_AS, show.getShowAs());
		}
		if (show.getShortForm() != null) {
			out.writeAttribute(Show.ATTRIBUTE_SHORT_FORM, show.getShortForm());
		}
	}
	
	public static void writeSrc(Output out,Src src) throws IOException {
		if (src.getSrc() == null) {
			LOGGER.warn("Attribute ["+ Src.ATTRIBUTE_SRC+ "] from Object [{}] must be not null !!! -> invalid content",src);
			return;
		} else {
			out.writeAttribute(Src.ATTRIBUTE_SRC, src.getSrc());
		}
		if (src.getAlt() != null) {
			out.writeAttribute(Src.ATTRIBUTE_ALT, src.getAlt());
		}
	}
	
	public static void writeIdReq(Output out,IdReq idReq) throws IOException {
		if (idReq.getId() == null) {
			LOGGER.warn("Attribute [id] from Object [{}] must be not null !!! -> invalid content",idReq);
			return;
		} else {
			out.writeAttribute(IdReq.ATTRIBUTE_ID, idReq.getId());
		}
		if (idReq.getEvolvingId() != null) {
			out.writeAttribute(IdReq.ATTRIBUTE_EVOLVING_ID,idReq.getEvolvingId());
		}
	}

	public static void writeName(Output out, Name name) throws IOException {
		if (name.getName() == null) {
			LOGGER.warn("Attribute [" + Name.ATTRIBUTE + "] from Object [{}] must be not null !!! -> invalid content",name);
			return;
		} else {
			out.writeAttribute(Name.ATTRIBUTE, name.getName());
		}
	}
	
	public static void writeLink(Output out,Link link) throws IOException {
		if (link.getHref()== null) {
			LOGGER.warn("Attribute [href] from Object [{}] must be not null !!! -> invalid content",link);
			return;
		} else {
			out.writeAttribute(Link.ATTRIBUTE, link.getHref());
		}
	}
	
	public static void writeLinkOpt(Output out,LinkOpt linkOpt) throws IOException {
		if (linkOpt.getHref() != null) {
			out.writeAttribute(LinkOpt.ATTRIBUTE, linkOpt.getHref() );
		}
	}
	
	public static void writePos(Output out,Pos pos) throws IOException {
		if (pos.getPos() != null) {
			out.writeAttribute(Pos.ATTRIBUTE, pos.getPos().name() );
		}
	}
	
	public static void writeRole(Output out,Role role) throws IOException {
		if (role.getAs() != null) {
			out.writeAttribute(Role.ATTRIBUTE, role.getAs());
		}
	}
	
	public static void writeActor(Output out,Actor actor) throws IOException {
		if (actor.getActor() != null) {
			out.writeAttribute(Actor.ATTRIBUTE, actor.getActor());
		}
	}
	
	public static void writeValue(Output out,Value value) throws IOException {
		if (value.getValue() == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",Value.ATTRIBUTE,value);
			return;
		} else {
			out.writeAttribute(Value.ATTRIBUTE, value.getValue());
		}
	}
	
	public static void writeOptValue(Output out,OptValue value) throws IOException {
		if (value.getValue() != null) {
			out.writeAttribute(OptValue.ATTRIBUTE,value.getValue());
		}
	}
	
	public static void writeTime(Output out,Time time) throws IOException {
		if (time.getTime() == null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",Time.ATTRIBUTE,time);
			return;
		} 
		
		StringBuilder builder = new StringBuilder();
		builder.append(time.getTime().get(Calendar.YEAR)).append("-");
		int temp = time.getTime().get(Calendar.MONTH)+1;
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append("-");
		temp =  time.getTime().get(Calendar.DAY_OF_MONTH);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp);
		builder.append("T");
		temp =  time.getTime().get(Calendar.HOUR_OF_DAY);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append(":");
		
		temp =  time.getTime().get(Calendar.MINUTE);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append(":");
		
		temp =  time.getTime().get(Calendar.SECOND);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp);
		
		out.writeAttribute(Time.ATTRIBUTE, builder.toString());
		
	}
	
	public static void writeSource(Output out,Source source) throws IOException {
		if (source.getSource()== null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",Source.ATTRIBUTE,source);
			return;
		} else {
			out.writeAttribute(Source.ATTRIBUTE, source.getSource());
		}
	}
	
	public static void writeNotes(Output out,Notes notes) throws IOException {
		if (notes.getMarker() != null) {
			out.writeAttribute(Notes.ATTRIBUTE_MARKER,notes.getMarker());
		}
		if (notes.getPlacement() != null) {
			out.writeAttribute(Notes.ATTRIBUTE_PLACEMENT,notes.getPlacement().name());
		}
		if (notes.getPlacementBase() != null) {
			out.writeAttribute(Notes.ATTRIBUTE_PLACEMENT_BASE,notes.getPlacementBase());
		}
	}
	
	public static void writeNumber(Output out,Number number) throws IOException {
		if (number.getNumber()== null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",Number.ATTRIBUTE,number);
			return;
		} else {
			out.writeAttribute(Number.ATTRIBUTE, number.getNumber());
		}
	}
	
	public static void writeDate(Output out, Date date) throws IOException {
		if (date.getDate()== null) {
			LOGGER.warn("Attribute [{}] from Object [{}] must be not null !!! -> invalid content",Date.ATTRIBUTE,date);
			return;
		}
		StringBuilder builder = new StringBuilder();
		builder.append(date.getDate().get(Calendar.YEAR)).append("-");
		int temp = date.getDate().get(Calendar.MONTH)+1;
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp).append("-");
		temp = date.getDate().get(Calendar.DAY_OF_MONTH);
		if (temp < 10) {
			builder.append("0");
		}
		builder.append(temp);
		out.writeAttribute(Date.ATTRIBUTE, builder.toString());
	}
}